import { PERMISSION_KEY_ORG } from '@/constants';
import { getOrgTrees } from '@/services/system/org';
import { Access, useAccess, useRequest } from '@umijs/max';
import { Input, Tree, message, theme } from 'antd';
import { DataNode } from 'antd/es/tree';
import React, { Key, useImperativeHandle, forwardRef, useState, useMemo, useEffect } from 'react';

interface Props {
  onSelect?: (selectedKeys: React.Key[]) => void;
  selectedKeys?: Key[];
  style?: React.CSSProperties;
  checkPermission?: boolean;
  fieldNames?: {
    title?: string;
    key?: string;
    children?: string;
  };
}

export type OrgTreeRefType = { refresh: () => void };

const searchParentKeys = (
  tree: API.OrgTreeNode[],
  searchValue: string,
  selectedKeys: React.Key[],
  wrap: Set<React.Key> = new Set(),
): Set<React.Key> => {
  if (searchValue === '' && selectedKeys.length <= 0) {
    return wrap;
  }
  tree.forEach((item) => {
    if ((searchValue && item.label.indexOf(searchValue) !== -1) || selectedKeys.includes(item.id)) {
      wrap.add(item.parentId);
    }
    if (item.children) {
      searchParentKeys(item.children, searchValue, selectedKeys, wrap);
    }
  });

  return wrap;
};

const OrgTree = forwardRef<OrgTreeRefType, Props>(
  (
    {
      onSelect,
      selectedKeys: insertSelectedKeys,
      style,
      checkPermission = true,
      fieldNames = {
        title: 'label',
        key: 'id',
        children: 'children',
      },
    },
    ref,
  ) => {
    if (!fieldNames.key) {
      fieldNames.key = 'id';
    }
    if (!fieldNames.title) {
      fieldNames.title = 'label';
    }
    // 权限控制
    const access = useAccess();
    const { data, error, refresh } = useRequest(getOrgTrees, {
      manual: !(checkPermission && PERMISSION_KEY_ORG.list && PERMISSION_KEY_ORG.list
        ? access.permissionFilter(PERMISSION_KEY_ORG.list)
        : true),
    });
    const [expandedKeys, setExpandedKeys] = useState<React.Key[]>([]);
    const [searchValue, setSearchValue] = useState('');
    const [selectedKeys, setSelectedKeys] = useState<React.Key[]>(insertSelectedKeys || []);
    useEffect(() => {
      if (insertSelectedKeys) {
        setSelectedKeys(insertSelectedKeys);
      }
    }, [insertSelectedKeys]);

    const { useToken } = theme;
    const { token } = useToken();
    useImperativeHandle(
      ref,
      () => ({
        refresh: () => {
          refresh();
          setSearchValue('');
        },
      }),
      [refresh],
    );

    const onChange = (e: React.ChangeEvent<HTMLInputElement>) => {
      const { value } = e.target;
      const newExpandedKeys = searchParentKeys(data || [], value, selectedKeys || []);
      setExpandedKeys(Array.from(newExpandedKeys));
      setSearchValue(value);
    };

    const treeData = useMemo(() => {
      const loop = (data: API.OrgTreeNode[]): API.OrgTreeNode[] =>
        data.map((item) => {
          const strTitle = item.label;
          const index = strTitle.indexOf(searchValue);
          const beforeStr = strTitle.substring(0, index);
          const afterStr = strTitle.slice(index + searchValue.length);
          const label =
            index > -1 ? (
              <span>
                {beforeStr}
                <span style={{ color: token.colorPrimary }}>{searchValue}</span>
                {afterStr}
              </span>
            ) : (
              <span>{strTitle}</span>
            );
          if (item.children) {
            return {
              ...item,
              label: label as unknown as string,
              id: item.id,
              children: loop(item.children),
            };
          }

          return {
            ...item,
            label: label as unknown as string,
            id: item.id,
          };
        });
      return loop(data || []);
    }, [searchValue, data]);

    if (error) {
      message.error(error.message);
      console.error('error', error);
    }

    return (
      <Access
        accessible={
          checkPermission && PERMISSION_KEY_ORG.list && PERMISSION_KEY_ORG.list
            ? access.permissionFilter(PERMISSION_KEY_ORG.list)
            : true
        }
      >
        <div style={style}>
          <Input placeholder="搜索机构" value={searchValue} onChange={onChange} />
          <Tree
            style={{
              marginTop: token.margin,
            }}
            fieldNames={fieldNames}
            expandAction={false}
            showIcon={false}
            treeData={treeData as unknown as DataNode[]}
            selectedKeys={selectedKeys}
            onSelect={(selectedKeysValue, info) => {
              const newSelectedKeys = [...selectedKeysValue];
              if (!newSelectedKeys.includes(info.node.key)) {
                newSelectedKeys.push(info.node.key);
              }
              setSelectedKeys(newSelectedKeys);
              if (onSelect) {
                onSelect(newSelectedKeys);
              }
            }}
            expandedKeys={expandedKeys}
            onExpand={(expandedKeysValue) => {
              setExpandedKeys(expandedKeysValue);
            }}
          />
        </div>
      </Access>
    );
  },
);

export default OrgTree;
